#include "fxcc/core/graph/common/ModelImporter.h"
#include "fxcc/core/graph/common/ShaderLoader.h"


ModelMetaCacheFile ModelImporter::m_ModelMetaData;
std::string ModelImporter::m_ModelMetaPath = ".metamap/model.metamap";

std::string ModelImporter::m_MeshPath = { "Mesh" };
std::string ModelImporter::m_AnimPath = { "Animation" };
std::string ModelImporter::m_MaterialPath = { "Material" };
std::string ModelImporter::m_BonePath = { "Bones" };

bool ModelImporter::ImportFile(const fxcc::File& file)
{

	if (!file.IsModel())
	{
		return false;
	}

	ztclog::info("[%s] import file %s", m_Name.c_str(), file.m_RelativePath.c_str());

	std::string _p = file.m_RelativePath;

	auto& m_MetaCache = m_ModelMetaData.m_ModelMetaCache[file.m_RelativePath];
	m_MetaCache = {};

	MetaMapIndex metaMapIndex;
	metaMapIndex.SetNativePath(_p);

	static fxcc::yml::Serializer serializer;

	fs::path m_FilePath(m_LibraryPath);
	fs::path m_AssertDirPath(m_AssertPath);

	auto scene = std::make_shared<fxcc::graph::common::Scene>(_p);
	const std::string sceneName = scene->m_Name;

	{
		fs::path _meshdataDir = m_FilePath / fs::path(m_MeshPath);
		fs::path _boneDataDir = m_FilePath / fs::path(m_BonePath);

		for (int i = 0; i < scene->m_MeshDatas.size(); i++)
		{
			const auto& meshData = scene->m_MeshDatas[i];

			metaMapIndex.SetName(meshData->m_Name);
			metaMapIndex.SetMesh(_meshdataDir.string(), _p, i);
			FXCC_FAILED(meshData->m_GeoDataPtr->WriteToFile(metaMapIndex.m_TargetFilePath));
			m_MetaCache.m_MeshMetaIndexes.push_back(metaMapIndex);

			if (meshData->HasBones())
			{
				metaMapIndex.SetSkinned(_meshdataDir.string(), _p, i);

				FXCC_FAILED(meshData->m_SkinnedMeshDataPtr->WriteToFile(metaMapIndex.m_TargetFilePath));
				m_MetaCache.m_SkinnedMetaIndexes.push_back(metaMapIndex);

				metaMapIndex.SetBone(_boneDataDir.string(), _p, i);
				FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::Bones>(metaMapIndex.m_TargetFilePath, *meshData->m_Bones));
				m_MetaCache.m_BoneMetaIndexes.push_back(metaMapIndex);


			}

		}
	}

	{
		fs::path _p1 = m_FilePath / fs::path(m_MaterialPath);
		fs::path _p2 = m_AssertDirPath / fs::path(m_MaterialPath);

		for (int i = 0; i < scene->m_Materials.size(); i++)
		{
			auto inst = scene->m_Materials[i];

			metaMapIndex.SetName(inst->m_Name);
			metaMapIndex.SetMaterial(_p1.string(), _p, i);

			FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::MaterialData>(metaMapIndex.m_TargetFilePath, *inst));
			m_MetaCache.m_MaterialMetaIndexes.push_back(metaMapIndex);

			fxcc::graph::common::MaterialView materialView;
			materialView.m_NativeDataMap.m_Index = metaMapIndex;
			// Default Token
			materialView.m_EffectToken = ShaderLoader::m_DefaultToken;

			MetaMapIndex realMaterialMetaMapIndex;
			// Must set name firstly
			realMaterialMetaMapIndex.SetName(inst->m_Name);
			realMaterialMetaMapIndex.SetRealMaterial(_p2.string(), _p, i);
			
			FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::MaterialView>(realMaterialMetaMapIndex.m_TargetFilePath, materialView));
			m_MetaCache.m_RealMaterialMetaIndexes.push_back(realMaterialMetaMapIndex);
		}
	}

	{
		fs::path _p1 = m_FilePath / fs::path(m_AnimPath);

		for (int i = 0; i < scene->m_Animations.size(); i++)
		{
			auto inst = scene->m_Animations[i];

			metaMapIndex.SetName(inst->m_Name);
			metaMapIndex.SetAnimation(_p1.string(), _p, i);
			FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::Animation>(metaMapIndex.m_TargetFilePath, *inst));

			m_MetaCache.m_AnimationMetaIndexes.push_back(metaMapIndex);

		}
	}


	return true;
}

bool ModelImporter::Availed(const fxcc::File& file)
{
	return file.IsModel();
}

bool ModelImporter::SaveCache()
{
	fxcc::yml::Serializer serializer;
	FXCC_FAILED(serializer.EncodePath<ModelMetaCacheFile>(m_ModelMetaPath, m_ModelMetaData));
	return true;
};

bool ModelImporter::LoadCache()
{
	fxcc::yml::Serializer serializer;
	FXCC_FAILED(serializer.DecodePath<ModelMetaCacheFile>(m_ModelMetaPath, m_ModelMetaData));
	return true;
};


